/**
 * 
 */
package com.qcorm.util;

import com.qcorm.core.DBUtil;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * 代码生成工具
 */
public class CodeGen {

	private static Logger logger = Logger.getLogger(CodeGen.class.getName());

	private static final String TAB = "    ";
	private static String author = "cqin";
	private static String dbName = "qinxiaochu";
	private static String tableName = "FoodInfo";
	private static String dbType = "MySql";

	public static void main(String[] args) throws Exception {

		DBUtil db = new DBUtil(dbType, dbName);
		String sql = "";
		if ("SqlServer".equals(dbType)) {
			sql = "SELECT top 1 * FROM " + tableName;
		} else {
			sql = "SELECT * FROM `" + tableName + "` LIMIT 0, 1";
		}
		try {
			ResultSet rs = db.executeQuery(sql, null);
			ResultSetMetaData rsmd = rs.getMetaData();// rs为查询结果集
			String content = genCode(rsmd);

			File file = new File(firstCharToUpperCase(tableName + ".java"));
			createFile(file);
			writeContetToFile(file, content);
			logger.info("文件生产成功，请刷新目录");
		} catch (Exception e) {
			logger.error("生成代码异常", e);
		} finally {
			db.close();
		}
	}

	/**
	 * 生成的主方法
	 * @param rsmd
	 * @return
	 * @throws SQLException
	 */
	public static String genCode(ResultSetMetaData rsmd) throws SQLException {
		StringBuilder sb = new StringBuilder(300);
		sb.append("package test.com.qcorm.core;");
		sb.append("\r\n").append("import java.util.*;");
		sb.append("\r\n").append("import com.qcorm.core.BaseModel;");
		sb.append("\r\n").append("import com.qcorm.core.DaoParameter;");

		sb.append("\r\n").append("\r\n");

		sb.append("\r\n").append("/**");
		sb.append("\r\n").append("*<p>Description: </p>");
		sb.append("\r\n").append("* @author " + author);
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		sb.append("\r\n").append("* @date " + df.format(new Date()));
		sb.append("\r\n").append("*");
		sb.append("\r\n").append("*/");

		sb.append("\r\n").append(
				"public class " + firstCharToUpperCase(tableName) + " extends BaseModel {");

		sb.append("\r\n").append("\r\n");

		// 构�?�函�?
		sb.append("\r\n").append(TAB + "public " + firstCharToUpperCase(tableName) + "(){");
		sb.append("\r\n").append(TAB + TAB + "this.dbType=\"" + dbType + "\";");
		sb.append("\r\n").append(TAB + TAB + "this.keyName = \"foodID\";");
		sb.append("\r\n").append(
				TAB + TAB + "this.dbName = \"" + dbName + "\";");
		sb.append("\r\n").append(
				TAB + TAB + "this.tableName = \"" + tableName + "\";");
		sb.append("\r\n").append(TAB + "}");

		sb.append("\r\n").append("\r\n");

		int count = rsmd.getColumnCount();
		for (int i = 1; i <= count; i++) {

			String firstCharLowerCase = firstCharToLowerCase(rsmd
					.getColumnName(i));
			String firstCharUpperCase = firstCharToUpperCase(rsmd
					.getColumnName(i));
			String javaType = dbTypeToJavaType(rsmd.getColumnType(i));
			sb.append("\r\n").append(
					TAB + "private " + javaType + " " + firstCharLowerCase
							+ ";");

			sb.append("\r\n").append(
					TAB + "public " + javaType + " get" + firstCharUpperCase
							+ "() {");
			sb.append("\r\n").append(
					TAB + TAB + "return " + firstCharLowerCase + ";");
			sb.append("\r\n").append(TAB + "}");

			sb.append("\r\n").append(
					TAB + "public void set" + firstCharUpperCase + "("
							+ javaType + " " + firstCharLowerCase + ") {");
			sb.append("\r\n").append(
					TAB + TAB + "this." + firstCharLowerCase + " = "
							+ firstCharLowerCase + ";");
			sb.append("\r\n").append(TAB + "}");

			sb.append("\r\n").append("\n");
		}

		sb.append("\r\n").append("\n");

		// orm附加方法
		sb.append("\r\n")
				.append(TAB
						+ "/***************************The following are additional code for ORM*******************/");

		sb.append("\r\n").append("\n");

		for (int i = 1; i <= count; i++) {

			String firstCharLowerCase = firstCharToLowerCase(rsmd
					.getColumnName(i));
			String firstCharUpperCase = firstCharToUpperCase(rsmd
					.getColumnName(i));
			String javaType = dbTypeToJavaType(rsmd.getColumnType(i));

			sb.append("\r\n").append(TAB + "/**");
			sb.append("\r\n").append(TAB + "* ");
			sb.append("\r\n").append(TAB + "* @param isWhereCondition");
			sb.append("\r\n").append(TAB + "* @param value");
			sb.append("\r\n").append(TAB + "*/");
			sb.append("\r\n").append(
					TAB + "public void setORM_" + firstCharUpperCase
							+ "(Boolean isWhereCondition, " + javaType
							+ " value)");
			sb.append("\r\n").append(TAB + "{");
			sb.append("\r\n").append(
					TAB + TAB + "this." + firstCharLowerCase + " = value;");
			sb.append("\r\n")
					.append(TAB
							+ TAB
							+ "this.parameters.add(new DaoParameter(isWhereCondition,\""
							+ firstCharLowerCase + "\",value,"
							+ dbTypeToString(rsmd.getColumnType(i)) + "));");
			sb.append("\r\n").append(TAB + "}");
			sb.append("\r\n").append("\n");
		}
		sb.append("\r\n").append("}");

		return sb.toString();
	}

	/**
	 * 首字母转小写
	 * @param s
	 * @return
	 */
	public static String firstCharToLowerCase(String s) {
		if (Character.isLowerCase(s.charAt(0)))
			return s;
		else
			return (new StringBuilder())
					.append(Character.toLowerCase(s.charAt(0)))
					.append(s.substring(1)).toString();
	}

	/**
	 * 首字母转大写
	 * @param s
	 * @return
	 */
	public static String firstCharToUpperCase(String s) {
		if (Character.isUpperCase(s.charAt(0)))
			return s;
		else
			return (new StringBuilder())
					.append(Character.toUpperCase(s.charAt(0)))
					.append(s.substring(1)).toString();
	}

	/**
	 * int的dbType转换为String
	 * @param dbType
	 * @return
	 */
	public static String dbTypeToString(int dbType) {
		String result = "java.sql.Types.";
		switch (dbType) {

		case (int) Types.BIGINT:
			result += "BIGINT";
			break;

		case (int) Types.BOOLEAN:
			result += "BOOLEAN";
			break;

		case (int) Types.BIT:
			result += "BIT";
			break;

		case (int) Types.VARCHAR:
		case (int) Types.DATE:
		case (int) Types.CHAR:
			result += "VARCHAR";
			break;

		case (int) Types.INTEGER:
			result += "INTEGER";
			break;
		case (int) Types.TIMESTAMP:
			result += "TIMESTAMP";
			break;

		case (int) Types.NVARCHAR:
			result += "NVARCHAR";
			break;
			
		case (int) Types.SMALLINT:
			result += "SMALLINT";
			break;
		case (int) Types.DECIMAL:
			result +="DECIMAL";
			break;
			
		case (int) Types.DOUBLE:
			result +="DOUBLE";
			break;
			
		case (int) Types.TINYINT:
			result +="TINYINT";
			break;
			
		default:
			logger.error("---------------------------------Wrong db type!!!" + dbType);
			break;
		}
		return result;
	}

	/**
	 * dbtyp转换为java类型
	 * @param dbType
	 * @return
	 */
	public static String dbTypeToJavaType(int dbType) {
		String result = "";
		switch (dbType) {

		case (int) Types.BIGINT:
			result = "long";
			break;

		case (int) Types.BOOLEAN:
		case (int) Types.BIT:
			result = "Boolean";
			break;

		case (int) Types.VARCHAR:
		case (int) Types.NVARCHAR:
			result = "String";
			break;

		case (int) Types.DATE:
		case (int) Types.TIMESTAMP:
				result = "Date";
				break;

		case (int) Types.CHAR:
			result = "char";
			break;

		case (int) Types.INTEGER:
			result = "int";
			break;



			
		case (int) Types.SMALLINT:
			result = "short";
			break;
			
		case (int) Types.DECIMAL:
			result ="BigDecimal";
			break;
			
		case (int) Types.DOUBLE:
			result ="Double";
			break;
			
		case (int) Types.TINYINT:
			result ="Short";
			break;

		default:
			logger.error("---------------------------------Wrong db type!!!" + dbType);
			break;
		}
		return result;
	}

	/**
	 * 创建文件
	 * 
	 * @param fileName
	 * @return
	 */
	public static boolean createFile(File fileName) {
		try {
			if (!fileName.exists()) {
				return  fileName.createNewFile();
			}else{
				return false;
			}
		} catch (Exception e) {
			logger.error("createFile exception", e);
			return false;
		}
	}

	/**
	 * 
	 * @param content
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public static void writeContetToFile(File fileName, String content) throws IOException {
		FileOutputStream o = null;
		try {
			o = new FileOutputStream(fileName);
			o.write(content.getBytes("utf-8"));

		} catch (Exception e) {
			logger.error("writeContetToFile exception", e);
		} finally {
			if(o != null){
				o.close();
			}
		}
	}

}
